import time
import itertools
import re
from datetime import datetime, timedelta
zbot.log("准备运行得物数据采集流程 2025.1.16 -- 邦桑迪")
zbot.log("--初始化--")
now = datetime.now()

excel_path = "/storage/emulated/0/Download/得物数据_"+now.strftime("%Y_%m_%d%H%M%S")+".xls"
config_path = "/storage/emulated/0/Download/得物配置.xls"

itemConstainsList = []
itemMaxSize = 0

# 重置设备状态
def resetDevice():
    zbot.automator.home()
    time.sleep(.5)
    zbot.automator.recents()
    time.sleep(.5)
    zbot.selector().id("clearAnimView").findOne().click()

# 滑动轨迹生成
def generate_coordinates(upEnd):
    steps = 10
    max_variation = 0.005
    wi = zbot.device.width
    hi = zbot.device.height
    max_variation = 0.005
    x_start = wi*0.82
    y_start = hi*0.7
    x_end = wi*0.8
    y_end = hi*upEnd
    x_step = (x_end - x_start) / steps
    y_step = (y_end - y_start) / steps

    coordinates = [500]
    for i in range(steps + 1):
        x = x_start + i * x_step + random.uniform(-max_variation, max_variation)
        y = y_start + i * y_step + random.uniform(-max_variation, max_variation)
        coordinates.append([round(x, 4), round(y, 4)])
    return coordinates

# 循环滑动查找点击
def findClickSelectorRandm(selector):
    found = zbot.selector().text(item).findOne()
    for i in range(0,10):
        if found:
            found.click()
            break
    else:
        zbot.automator.gesture(*generate_coordinates())
    zbot.stop("渐进点击失败")

# 判断是否七天
def is_within_seven_days(relative_time):
    if "分钟前" in relative_time:
        minutes = int(re.search('(\\d+)', relative_time).group(1))
        actual_time = now - timedelta(minutes=minutes)
    elif "小时前" in relative_time:
        hours = int(re.search('(\\d+)', relative_time).group(1))
        actual_time = now - timedelta(hours=hours)
    elif "天前" in relative_time:
        days = int(re.search('(\\d+)', relative_time).group(1))
        actual_time = now - timedelta(days=days)
    elif "月前" in relative_time:
        months = int(re.search('(\\d+)', relative_time).group(1))
        actual_time = now - timedelta(days=months*30)  # 近似处理
    elif re.match('\\d+月\\d+日', relative_time):
        month_day = re.search('(\\d+)月(\\d+)日', relative_time)
        month = int(month_day.group(1))
        day = int(month_day.group(2))
        actual_time = datetime(now.year, month, day)
    elif re.match('\\d{4}\\.\\d{2}\\.\\d{1,2}', relative_time):
        actual_time = datetime.strptime(relative_time, "%Y.%m.%d")
    else:
        actual_time = now
    return (now - actual_time).days <= 7

# 下载配置文件
def downloadExcel():
    if zbot.files.exists(config_path):
        zbot.log("发现文件")
        zbot.files.remove(config_path)
    res = zbot.cloudFile.list(1,20)
    for item in res.get("records"):
        if "得物数据配置" in item.get("fileName"):
            id = item.get("id")
            zbot.cloudFile.download(id,config_path)
            return True
    return False

# 读取配置文件
def readExcel():
    path = zbot.files.path(config_path)
    data = zbot.excel.read(path,"配置")
    return data

# 数据合并
def merge_arrays(old_array, new_array):
    if not old_array:
        return new_array
    for i in range(len(old_array)):
        if old_array[i:i + len(new_array)] == new_array[:len(old_array) - i]:
            return old_array + new_array[len(old_array) - i:]
    return old_array + new_array

# 打开得物
def startDeWu(keyList):
    zbot.log("启动得物")
    zbot.app.launchPackage('com.shizhuang.duapp')
    zbot.selector().id("iv_tab_user_dynamic").waitForOrStop("得物启动失败",10000)
    search(keyList)
    # 回写Excel

# 方法传入的是二维数组
def search(keyList):
    zbot.selector().id("flSearchB").findOne().click() # 点击搜索框
    for key in keyList[1:]:
        zbot.selector().id("etSearch").setText(key[0]) # 输入搜索关键词
        zbot.selector().text("搜索").findOne().click() # 点击搜索
        zbot.selector().text("商品").findOne().parent().click() # 选择商品
        zbot.selector().text("筛选").findOne().parent().click() # 点击筛选
        type = zbot.selector().id("nestParent").findOne().findOne(zbot.selector().text(key[1])) # 查找黄金
        if type:
            type.click() # 点击
            zbot.selector().textContains("确定（").findOne().click() # 确定
            # 此处开始循环点击
            loopGoods(int(key[2]))

        else:
            continue # 继续下一个搜索

# 循环商品
def loopGoods(itemMaxSize):
    itemConstainsList = []
    while(True):
        root_list = zbot.selector().id("search_root").find()
        for i in range(0,root_list.size()):
            item = root_list.get(i)
            title = item.findOne(zbot.selector().id("search_title")).text()
            price = item.findOne(zbot.selector().id("search_price")).text()
            itemFullText = f"{title}_{price}"
            if itemFullText in itemConstainsList:
                continue
            elif len(itemConstainsList) == itemMaxSize:
                break
            else:
                itemConstainsList.append(itemFullText)
                item.click()
                zbot.selector().id("buyButton").findOne().click()
                skuList = loopSKU()
                # 循环获取商品
                zbot.selector().id("buyButton").findOne().click()
                # 主数据
                skuList=getSkuInfo(skuList,0,"",[])
                # 获取最近七天数据
                buyList = lastSevenBuys()
                # 合并数据
                sku_dict = {sku[0]:sku for sku in skuList}
                for item in buyList:
                    sku = item[0]
                    if sku in sku_dict:
                        sku_dict[sku][2] +=1
                zbot.automator.back()
        if len(itemConstainsList) == itemMaxSize:
            break
        zbot.automator().swipeDown()


# 循环最近七天            
def lastSevenBuys():
    recyClerList = []
    temp_rec = []
    while True:
        recyclerView = zbot.selector().id("recyclerView").findOne()
        recList = []
        for i in range(0,recyclerView.childCount()):
            item = recyclerView.child(i)
            if item.findOne(zbot.selector().id("tvRecentName")):
                buyName = item.findOne(zbot.selector().id("tvRecentName")).text()
                buySize = item.findOne(zbot.selector().id("tvRecentSize")).text()
                buyPrice = item.findOne(zbot.selector().id("tvRecentPrice")).text()
                buyTime = item.findOne(zbot.selector().id("tvRecentDate")).text()
                if is_within_seven_days(buyTime):
                    recyInfo = buyName + buySize + buyPrice + buyTime
                    recList.append(recyInfo)
        recyClerList = merge_arrays(recyClerList,recList)
       # writeExcel(newRecy)
        zbot.log(len(recyClerList))
        if recList == temp_rec:
            break
        else:
            temp_rec = recList
        zbot.automator.gesture(*generate_coordinates(0.4))   
        zbot.sleep(3000)
    zbot.automator.back()
    return recyClerList

# 回写到表格中并且上传
def writeExcel(dataArray):
    excel_path = zbot.files.path(excel_path)
    # zbot.files.ensureDir(excel_path)
    excelObj = zbot.excel.open(excel_path,"数据")
    zbot.excel.write(excel_path, "数据", dataArray)
    zbot.excel.syncDisk(excel_path)
# 上传数据结果
def uploadFile():
    res = zbot.cloudFile.uploadV2(excel_path,excel_path,True,"手机采集数据结果.xlsx")
    if res.get("code") == 0:
        return True
    else:
        return False
    
# 获取sku的价格信息
def getSkuInfo(skuParam,level,skuText,skuList):
    for key in skuParam[level].keys():
        for item in skuParam[level].get(key):
            if level == 0:
                zbot.selector().id("closeIcon").findOne().click()
                zbot.selector().id("buyButton").findOne().click()
            findClickSelectorRandm(zbot.selector().text(item))
            if level+1 < len(skuParam):
                getSkuInfo(skuParam,level+1,skuText + item,skuList)
            if level == len(skuParam):
                # 获取数据并写入数据列表
                price = zbot.selector().id("tvPrice").findOne().text()
                sku = zbot.selector().id("itemSelectedProperty").findOne().text().replace("已选","").replace(" ","")
                skuList.append([sku,price,0])
    return skuList
# 循环获取所有sku
def loopSKU():
    findType = False
    raw_data = []
    lable = ""
    while(True):
        for i in range(0,zbot.selector().id("layDialogContent").findOne().childCount()):
            layChild = zbot.selector().id("layDialogContent").findOne().child(i)
            if layChild.child(0).id() == "com.shizhuang.duapp:id/layItemContainer":
                tvName = layChild.findOne(zbot.selector().id("tvName")).text()
                if tvName:
                    found = any(tvName in values for item in raw_data for values in item.values())
                    if found:
                        findType = True
                    else:
                        for item in raw_data:
                            if lable in item:
                                item[lable].append(tvName)
                                break
                        findType = False

            else:
                # 不是对应款式的处理 
                title = layChild.child(0).child(0).child(0).text()
                found = any(title in item for item in raw_data)
                if found:
                    lable = title
                else:
                    lable = title
                    raw_data.append({title:[]})
        zbot.automator.swipeDown()
        zbot.sleep(1000)
        if findType:
            # 循环跑完了最后一个都找到了，代表下滑完成了 可以跳出
            break
    zbot.selector().id('closeIcon').findOne().click()
    zbot.sleep(1000)
    return raw_data
 

def findClickSelectorRandm(selector):
    found = selector.findOne()
    for i in range(0,10):
        if found:
            zbot.sleep(500)
            found.parent().click()
            return
    else:
        zbot.automator.gesture(*generate_coordinates())

def generate_coordinates():
    steps = 10
    max_variation = 0.005
    wi = zbot.device.width
    hi = zbot.device.height
    max_variation = 0.005
    x_start = wi*0.82
    y_start = hi*0.7
    x_end = wi*0.8
    y_end = hi*0.65
    x_step = (x_end - x_start) / steps
    y_step = (y_end - y_start) / steps

    coordinates = [500]
    for i in range(steps + 1):
        x = x_start + i * x_step + random.uniform(-max_variation, max_variation)
        y = y_start + i * y_step + random.uniform(-max_variation, max_variation)
        coordinates.append([round(x, 4), round(y, 4)])
    return coordinates

resetDevice() # 重置手机状态
downloadExcel()
startDeWu(readExcel())
